package lt.vu.spf.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.swing.BoxLayout;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

import lt.vu.spf.graph.Edge;
import lt.vu.spf.graph.Graph;
import lt.vu.spf.graph.Vertex;

/**
 * @author Mantas Sinkevičius
 */
public class MainWindow extends JFrame {
    private static final long serialVersionUID = 6399812859731622842L;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {

                final Graph graph = new Graph();

                final MainWindow window = new MainWindow();
                window.setLayout(new BorderLayout());
                window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                window.setTitle("Graičiausio kelio paieška");

                final Canvas canvas = new Canvas(graph);
                canvas.setLayout(new BoxLayout(canvas, 1));
                canvas.setPreferredSize(new Dimension(1024, 768));
                JScrollPane scrollPane = new JScrollPane(canvas);
                canvas.setBackground(Color.WHITE);

                final Menu menuBar = new Menu();
                window.setJMenuBar(menuBar);
                window.getContentPane().add(scrollPane);
                window.pack();
                window.setSize(1024, 768);
                window.setVisible(true);

                // Paspaudus dešinį pelės klavišą pridėti viršūnę, jeigu prieš tai nebuvo pažymėta jokia viršūnė.
                // Jeigu viršūnė buvo pažymėta - nebežymėti jokios viršūnės.
                canvas.addMouseListener(new MouseAdapter() {
                    /**
                     * Ar viršūnė nepersikerta su kuria nors kita grafo viršūne.
                     * @param vertex viršūnė kuri tikrinama
                     * @return
                     */
                    private boolean doesNotCollide(Vertex vertex) {
                        boolean canDraw = true;
                        for (Vertex v : graph.getVertices()) {
                            canDraw = canvas.buildCircle(vertex).intersects(canvas.buildCircle(v).getBounds2D()) ? false
                                    : true;
                            if (canDraw == false) {
                                return canDraw;
                            }
                        }
                        return canDraw;
                    }

                    @Override
                    public void mouseReleased(MouseEvent e) {
                        if (e.getButton() == MouseEvent.BUTTON3) {
                            Vertex newVertex = new Vertex(e.getX(), e.getY());
                            if (graph.getSelectedVertex() == null && graph.getSelectedEdge() == null
                                    && doesNotCollide(newVertex)) {
                                graph.addVertex(newVertex);
                            } else {
                                graph.setSelectedVertex(null);
                                graph.setSelectedEdge(null);
                            }
                            canvas.repaint();
                        }
                    }
                });

                // Paspaudus kairį pelės klavišą ant viršūnės ją pasirinkti, o jeigu jau prieš tai buvo pasirinkta kita viršūnė jas abi sujungti.
                canvas.addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseReleased(MouseEvent e) {
                        if (e.getButton() == MouseEvent.BUTTON1) {
                            for (Vertex vertex : graph.getVertices()) {
                                if (canvas.buildCircle(vertex).contains(e.getX(), e.getY())) {
                                    if (graph.getSelectedVertex() != null) {
                                        // Jei prieš tai buvo pasirinkta kita viršūnė, jos sujungiamos
                                        graph.connectVertices(graph.getSelectedVertex(), vertex);
                                    }
                                    graph.setSelectedVertex(vertex);
                                    graph.setSelectedEdge(null);
                                    break;
                                } else {
                                    // Jei nepasirinkta viršūnė tikrinama ar pasitinkta briauna
                                    for (Edge edge : graph.getEdges()) {
                                        if (canvas.buildLine(edge).intersects(e.getX(), e.getY(), 5, 5)) {
                                            // Kadangi briauna yra labai plona, jos pasirinkimui užtenka pataikyt į 5px plotą aplinkui.
                                            if (e.getClickCount() == 2 && !e.isConsumed()) {
                                                // Jei tai dvigubas pelės paspaudimas leidžiama įvesti briaunos svorį
                                                e.consume();
                                                String weight = JOptionPane.showInputDialog(null, "Briaunos svoris", 1);
                                                if (weight != null) {
                                                    edge.setWeight(Float.parseFloat(weight));
                                                    break;
                                                }
                                            }
                                            graph.setSelectedEdge(edge);
                                            graph.setSelectedVertex(null);
                                            break;
                                        }
                                    }
                                }
                            }
                            canvas.repaint();
                        }
                    }
                });

                // Rodomas išsaugojimo dialogas.
                menuBar.getjMenuItem11().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent actionEvent) {
                        JFileChooser fc = new JFileChooser();
                        fc.setSelectedFile(new File("untitled.spf"));
                        ActionListener actionListener = new ActionListener() {
                            public void actionPerformed(ActionEvent actionEvent) {
                                if (actionEvent.getActionCommand().equals(JFileChooser.APPROVE_SELECTION)) {
                                    // gaunamas naujo failo pavadinimas
                                    File file = ((JFileChooser) actionEvent.getSource()).getSelectedFile();
                                    try {
                                        // grafas įrašomas į failą
                                        FileOutputStream fileOut = new FileOutputStream(file);
                                        ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
                                        objectOut.writeObject(canvas.getGraph());
                                        objectOut.close();
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        };
                        fc.addActionListener(actionListener);
                        fc.showSaveDialog(null);
                    }
                });

                // Rodomas įkelimo dialogas.
                menuBar.getjMenuItem12().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent actionEvent) {
                        JFileChooser fc = new JFileChooser();
                        ActionListener actionListener = new ActionListener() {
                            public void actionPerformed(ActionEvent actionEvent) {
                                if (actionEvent.getActionCommand().equals(JFileChooser.APPROVE_SELECTION)) {
                                    // gaunamas naujo failo pavadinimas
                                    File selectedFile = ((JFileChooser) actionEvent.getSource()).getSelectedFile();
                                    FileInputStream fin;
                                    try {
                                        // nuskaitomas failas
                                        fin = new FileInputStream(selectedFile);
                                        ObjectInputStream ois = new ObjectInputStream(fin);
                                        Graph g = (Graph) ois.readObject();
                                        ois.close();
                                        // įkeliamos grafo viršūnės ir briaunos
                                        graph.setVertices(g.getVertices());
                                        graph.setEdges(g.getEdges());
                                        canvas.repaint();
                                    } catch (IOException | ClassNotFoundException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        };
                        fc.addActionListener(actionListener);
                        fc.showOpenDialog(null);
                    }
                });

                // Rodomas žemėlapio įkelimo dialogas.
                menuBar.getjMenuItem13().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        JFileChooser fc = new JFileChooser();
                        ActionListener actionListener = new ActionListener() {
                            public void actionPerformed(ActionEvent actionEvent) {
                                String command = actionEvent.getActionCommand();
                                if (command.equals(JFileChooser.APPROVE_SELECTION)) {
                                    // užkraunamas naujai įkeltas rastrinis žemėlapis
                                    File selectedFile = ((JFileChooser) actionEvent.getSource()).getSelectedFile();
                                    canvas.loadImage(selectedFile);
                                }
                            }
                        };
                        fc.addActionListener(actionListener);
                        fc.showOpenDialog(null);
                    }
                });

                // Sujungia visas viršūnes.
                menuBar.getjMenuItem21().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        graph.connectAllVertices();
                        canvas.repaint();
                    }
                });

                // Sujungia viršūnes paeiliui.
                menuBar.getjMenuItem22().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        graph.connectVerticesByOrder();
                        canvas.repaint();
                    }
                });

                // Nuspėja kelio pradžią ir pabaigą.
                menuBar.getjMenuItem23().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        graph.guessRoute();
                        canvas.repaint();
                    }
                });

                // Paspaudus, rasti trumpiausią kelią.
                menuBar.getjMenuItem31().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        graph.findShortestPath();
                        canvas.repaint();
                    }
                });

                // Pasirinkus, rodyti viršūnių koordinates.
                menuBar.getjMenuItem32().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        if (canvas.getConfig().contains(ConfigEnum.SHOW_VERTICES_COORDINATES)) {
                            canvas.getConfig().remove(ConfigEnum.SHOW_VERTICES_COORDINATES);
                        } else {
                            canvas.getConfig().add(ConfigEnum.SHOW_VERTICES_COORDINATES);
                        }
                        canvas.repaint();
                    }
                });

                // Pasirinkus, rodyti briaunų svorius.
                menuBar.getjMenuItem33().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        if (canvas.getConfig().contains(ConfigEnum.SHOW_EDGE_WEIGHTS)) {
                            canvas.getConfig().remove(ConfigEnum.SHOW_EDGE_WEIGHTS);
                        } else {
                            canvas.getConfig().add(ConfigEnum.SHOW_EDGE_WEIGHTS);
                        }
                        canvas.repaint();
                    }
                });

                // Paspaudus, ištrinti pasirinktą viršūnę arba briauną
                menuBar.getjMenuItem41().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        if (graph.getSelectedVertex() != null) {
                            graph.removeSelectedVertex();
                        } else if (graph.getSelectedEdge() != null) {
                            graph.removeSelectedEdge();
                        }
                        canvas.repaint();
                    }
                });

                // Paspaudus, pasirinktą viršūnę pasirinkti kaip kelio pradžią
                menuBar.getjMenuItem43().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        if (graph.getSelectedVertex() != null) {
                            graph.setStartingVertex(graph.getSelectedVertex());
                            canvas.repaint();
                        }
                    }
                });

                // Paspaudus, pasirinktą viršūnę pasirinkti kaip kelio pabaigą
                menuBar.getjMenuItem44().addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent event) {
                        if (graph.getSelectedVertex() != null) {
                            graph.setDestinationVertex(graph.getSelectedVertex());
                            canvas.repaint();
                        }
                    }
                });

            }
        });
    }
}
